home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Utilities / MView / gxu / npatchoutline.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-30  |  12.0 KB  |  399 lines

  1. /*//////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: stripoutline.cpp
  4. //
  5. // Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  6. //
  7. //
  8. //////////////////////////////////////////////////////////////////////////////*/
  9.  
  10. #include "pchgxu.h"
  11.  
  12. #include "NPatchOutline.h"
  13.  
  14. CNPatchOutline::CNPatchOutline()
  15.   :m_pDevice(NULL),
  16.     m_pIndexBuffer(NULL),
  17.     m_rgaeAttributeTable(NULL),
  18.     m_caeAttributeTable(0),
  19.     m_pDeclObj(NULL),
  20.     m_bEmulate32BitIndex(FALSE)
  21. {
  22. }
  23.  
  24. CNPatchOutline::~CNPatchOutline()
  25. {
  26.     GXRELEASE(m_pIndexBuffer);
  27.     GXRELEASE(m_pDevice);
  28.     GXRELEASE(m_pDeclObj);
  29.  
  30.     delete []m_rgaeAttributeTable;
  31. }
  32.  
  33. // -------------------------------------------------------------------------------
  34. //  method    CalculateCounts
  35. //
  36. //  devnote     Calculates the number of vertices and faces for a bezier triangle
  37. //                  that is tessellated with the given level
  38. //
  39. //  returns     S_OK if suceeded, else error code
  40. //
  41. static void 
  42. CalculateCounts(DWORD cSegments, PDWORD pcFaces)
  43. {
  44.     DWORD iLevel;
  45.     DWORD cFacesPrev;
  46.     DWORD cFacesOut;
  47.  
  48.  
  49.     // UNDONE - should be a convenient formula to figure this one out
  50.     cFacesOut = 1;
  51.     cFacesPrev = 1;
  52.     for (iLevel = 0; iLevel < cSegments-1; iLevel++)
  53.     {
  54.         cFacesPrev += 2;
  55.         cFacesOut += cFacesPrev;
  56.     }
  57.  
  58.     *pcFaces = cFacesOut;
  59. }
  60.  
  61.  
  62. template<class UINT_IDX>
  63. void AddOutlineLineSegments(UINT_IDX *pwNPatchFaceIndices, DWORD cSegments, UINT_IDX *pwLineIndicesOut)
  64. {
  65.     DWORD cFacesCurLine;
  66.     DWORD iLevel;
  67.     DWORD iFaceCur;
  68.  
  69.     UINT_IDX *pwLineIndicesOrig = pwLineIndicesOut;
  70.  
  71.     // first deal with all triangles up to the last "strip" of tesselate triangles (three sides of lines, not just two for that row)
  72.     cFacesCurLine = 1;
  73.     for (iLevel = 0; iLevel < cSegments-1; iLevel++)
  74.     {
  75.         // Add the left edge
  76.         *pwLineIndicesOut = pwNPatchFaceIndices[0];
  77.         pwLineIndicesOut++;
  78.         *pwLineIndicesOut = pwNPatchFaceIndices[1];
  79.         pwLineIndicesOut++;
  80.  
  81.         // skip the interior triangles of this strip
  82.         pwNPatchFaceIndices += 3 * (cFacesCurLine - 1);
  83.  
  84.         // add the right edge
  85.         *pwLineIndicesOut = pwNPatchFaceIndices[0];
  86.         pwLineIndicesOut++;
  87.         *pwLineIndicesOut = pwNPatchFaceIndices[2];
  88.         pwLineIndicesOut++;
  89.         pwNPatchFaceIndices += 3;
  90.  
  91.         cFacesCurLine += 2;        
  92.     }
  93.  
  94.     // add the left edge
  95.     *pwLineIndicesOut = pwNPatchFaceIndices[0];
  96.     pwLineIndicesOut++;
  97.     *pwLineIndicesOut = pwNPatchFaceIndices[1];
  98.     pwLineIndicesOut++;
  99.  
  100.     // add the bottom edges of all triangles in the middle of the bottom strip
  101.     if (cFacesCurLine > 1)
  102.     {
  103.         // add the bottom edge
  104.         for (iFaceCur = 0; iFaceCur < cFacesCurLine - 2; iFaceCur += 2)
  105.         {
  106.             *pwLineIndicesOut = pwNPatchFaceIndices[1];
  107.             pwLineIndicesOut++;
  108.             *pwLineIndicesOut = pwNPatchFaceIndices[2];
  109.             pwLineIndicesOut++;
  110.  
  111.             pwNPatchFaceIndices += 6;
  112.         }
  113.     }
  114.  
  115.     // add the right edge of the last triangle
  116.     *pwLineIndicesOut = pwNPatchFaceIndices[0];
  117.     pwLineIndicesOut++;
  118.     *pwLineIndicesOut = pwNPatchFaceIndices[2];
  119.     pwLineIndicesOut++;
  120.  
  121.     // add the bottom edge of the last triangle
  122.     *pwLineIndicesOut = pwNPatchFaceIndices[1];
  123.     pwLineIndicesOut++;
  124.     *pwLineIndicesOut = pwNPatchFaceIndices[2];
  125.     pwLineIndicesOut++;
  126.  
  127.     GXASSERT(pwLineIndicesOrig + cSegments * 2 * 3 == pwLineIndicesOut);
  128. }
  129.  
  130. HRESULT
  131. CNPatchOutline::Init(ID3DXBaseMesh *ptmMesh, DWORD cTesselateSegments)
  132. {
  133.     HRESULT hr = S_OK;
  134.     BOOL b16BitIndex;
  135.     DWORD cBytesPerIndex;
  136.     DWORD iPoint;
  137.     DWORD iOrigFace;
  138.     DWORD cFaces;
  139.     DWORD cOrigFaces;
  140.     D3DXATTRIBUTERANGE *rgaeAttributeTableMesh = NULL;
  141.     DWORD *rgdwAttr = NULL;
  142.     PBYTE pbFaceIndices = NULL;
  143.     PBYTE pbLineIndices = NULL;
  144.     PBYTE pbSrc;
  145.     PBYTE pbDest;
  146.     DWORD iLineOffset;
  147.     DWORD iAttr;
  148.     DWORD dwNeighbor;
  149.     DWORD iFaceEnd;
  150.     BOOL bCrease;
  151.     DWORD cFacesCur;
  152.     D3DCAPS9 Caps;
  153.     PBYTE pbFaceIndicesCur;
  154.     PBYTE pbLineIndicesCur;
  155.     DWORD cNPatchFacesPerFace;
  156.  
  157.     // is the mesh 16 bit?
  158.     b16BitIndex = !(ptmMesh->GetOptions() & D3DXMESH_32BIT);
  159.     cBytesPerIndex = (b16BitIndex ? 2:4);
  160.  
  161.     // get the number of faces
  162.     cFaces = ptmMesh->GetNumFaces();
  163.  
  164.     hr = CreateEmptyOutline();
  165.     if (FAILED(hr))
  166.         goto e_Exit;
  167.  
  168.     ptmMesh->GetDeclaration(m_pDecl);
  169.     m_cBytesPerVertex = D3DXGetDeclVertexSize(m_pDecl, 0);
  170.  
  171.     ptmMesh->GetDevice(&m_pDevice);
  172.  
  173.     hr = m_pDevice->CreateVertexDeclaration(m_pDecl, &m_pDeclObj);
  174.     if (FAILED(hr))
  175.         goto e_Exit;
  176.  
  177.  
  178.     hr = ptmMesh->GetAttributeTable(NULL, &m_caeAttributeTable);
  179.     if (FAILED(hr))
  180.         goto e_Exit;
  181.  
  182.     // check for no attribute table and/or no adjacency
  183.     if (m_caeAttributeTable == 0) 
  184.     {
  185.         // not attribute sorted!  just return for now
  186.         goto e_Exit;
  187.     }
  188.  
  189.     rgaeAttributeTableMesh = new D3DXATTRIBUTERANGE[m_caeAttributeTable];
  190.     m_rgaeAttributeTable = new D3DXATTRIBUTERANGE[m_caeAttributeTable];
  191.     if ((rgaeAttributeTableMesh == NULL) || (rgaeAttributeTableMesh == NULL))
  192.     {
  193.         hr = E_OUTOFMEMORY;
  194.         goto e_Exit;
  195.     }
  196.  
  197.     CalculateCounts(cTesselateSegments, &cNPatchFacesPerFace);
  198.     m_cLinesPerOrigFace = cTesselateSegments * 3;
  199.  
  200.     // should be the same number of new faces in relation to the old
  201.     GXASSERT((cFaces % cNPatchFacesPerFace) == 0);
  202.     cOrigFaces = cFaces / cNPatchFacesPerFace;
  203.  
  204.     hr = ptmMesh->GetAttributeTable(rgaeAttributeTableMesh, NULL);
  205.     if (FAILED(hr))
  206.         goto e_Exit;
  207.  
  208.     ptmMesh->LockIndexBuffer(D3DLOCK_READONLY, (LPVOID*)&pbFaceIndices);
  209.  
  210.     // now initialize the edge attribute table
  211.     cFacesCur = 0;
  212.     for (iAttr = 0; iAttr < m_caeAttributeTable; iAttr++)
  213.     {
  214.         m_rgaeAttributeTable[iAttr] = rgaeAttributeTableMesh[iAttr];
  215.  
  216.         // 3 * Segments primitives per original triangle - original triangle = NewFaces / NumNewFacesPerOld
  217.         m_rgaeAttributeTable[iAttr].FaceCount = (m_rgaeAttributeTable[iAttr].FaceCount / cNPatchFacesPerFace) * cTesselateSegments * 3;
  218.  
  219.         // setup the correct face start
  220.         m_rgaeAttributeTable[iAttr].FaceStart = cFacesCur;
  221.         cFacesCur += m_rgaeAttributeTable[iAttr].FaceCount;
  222.     }
  223.  
  224.     m_pDevice->GetDeviceCaps(&Caps);
  225.  
  226.     // if there are too many vertices, or the max vertex index is below 16bit (means no 32 bit support)
  227.     //    then we need to emulate
  228.     if (!b16BitIndex && ((Caps.MaxVertexIndex < ptmMesh->GetNumVertices()) || (Caps.MaxVertexIndex <= 0xffff) || (Caps.MaxPrimitiveCount < cFacesCur)))
  229.     {
  230.         m_bEmulate32BitIndex = TRUE;
  231.     }
  232.     else
  233.     {
  234.         m_bEmulate32BitIndex = FALSE;
  235.     }
  236.  
  237.     hr = m_pDevice->CreateIndexBuffer(cOrigFaces * 3 * cTesselateSegments * 2 * cBytesPerIndex, D3DUSAGE_SOFTWAREPROCESSING, 
  238.                                         (b16BitIndex ? D3DFMT_INDEX16:D3DFMT_INDEX32),
  239.                                         D3DPOOL_MANAGED, &m_pIndexBuffer, NULL);
  240.     if (FAILED(hr))
  241.         goto e_Exit;
  242.  
  243.     m_pIndexBuffer->Lock(0, 0, (PVOID*)&pbLineIndices, D3DLOCK_NOSYSLOCK);
  244.  
  245.  
  246.     // next go through and fill the index buffer
  247.     pbFaceIndicesCur = pbFaceIndices;
  248.     pbLineIndicesCur = pbLineIndices;
  249.     for (iOrigFace = 0; iOrigFace < cOrigFaces; iOrigFace++)
  250.     {
  251.         if (b16BitIndex)
  252.         {
  253.             AddOutlineLineSegments<UINT16>((UINT16*)pbFaceIndicesCur, cTesselateSegments, (UINT16*)pbLineIndicesCur);
  254.         }
  255.         else
  256.         {
  257.             AddOutlineLineSegments<UINT32>((UINT32*)pbFaceIndicesCur, cTesselateSegments, (UINT32*)pbLineIndicesCur);
  258.         }
  259.  
  260.         pbFaceIndicesCur += cBytesPerIndex * 3 * cNPatchFacesPerFace;
  261.         pbLineIndicesCur += cBytesPerIndex * 2 * 3 * cTesselateSegments;
  262.     }
  263.  
  264. e_Exit:
  265.     delete []rgaeAttributeTableMesh;
  266.     delete []rgdwAttr;
  267.  
  268.     if (pbFaceIndices != NULL)
  269.         ptmMesh->UnlockIndexBuffer();
  270.  
  271.     if (pbLineIndices != NULL)
  272.         m_pIndexBuffer->Unlock();
  273.  
  274.     return hr;
  275. }
  276.  
  277. HRESULT
  278. CNPatchOutline::DrawInternal(LPD3DXBASEMESH ptmDrawMesh, DWORD iAttrib, DWORD iStartIndex, DWORD cLines)
  279. {
  280.     HRESULT hr;
  281.     LPDIRECT3DVERTEXBUFFER9 pVertexBuffer;
  282.     DWORD cBytesPerVertex;
  283.     DWORD dwFVF;
  284.     DWORD iSubset;
  285.  
  286.     DWORD *pdwLineIndices;
  287.     PBYTE pbLine;
  288.     PBYTE pbPoints;
  289.     DWORD iLine;
  290.     DWORD iLineStart;
  291.     DWORD iLineEnd;
  292.  
  293.     if ((iAttrib < m_caeAttributeTable) && (m_rgaeAttributeTable[iAttrib].AttribId == iAttrib))
  294.     {
  295.         iSubset = iAttrib;
  296.     }
  297.     else
  298.     {
  299.         // look for the correct attribute table entry to draw
  300.         for (iSubset = 0; iSubset < m_caeAttributeTable; iSubset++)
  301.         {
  302.             if (m_rgaeAttributeTable[iSubset].AttribId == iAttrib)
  303.             {
  304.                 break;
  305.             }
  306.         }
  307.     }
  308.  
  309.     if (iSubset < m_caeAttributeTable)
  310.     {
  311.         if ((iStartIndex == UNUSED32) || (cLines == UNUSED32))
  312.         {
  313.             iStartIndex = m_rgaeAttributeTable[iSubset].FaceStart;
  314.             cLines = m_rgaeAttributeTable[iSubset].FaceCount;
  315.         }
  316.  
  317.         if (m_rgaeAttributeTable[iSubset].FaceCount > 0)
  318.         {
  319.             if (!m_bEmulate32BitIndex)
  320.             {
  321.                 ptmDrawMesh->GetVertexBuffer(&pVertexBuffer);
  322.                 m_pDevice->SetVertexDeclaration(m_pDeclObj);
  323.                 m_pDevice->SetStreamSource(0, pVertexBuffer, 0, m_cBytesPerVertex);
  324.                 m_pDevice->SetIndices(m_pIndexBuffer);
  325.  
  326.                 hr = m_pDevice->DrawIndexedPrimitive(D3DPT_LINELIST, 
  327.                                              0, 0, m_rgaeAttributeTable[iSubset].VertexStart + m_rgaeAttributeTable[iSubset].VertexCount,
  328.                                              iStartIndex * 2, 
  329.                                              cLines);
  330.                 if (FAILED(hr))
  331.                     return hr;
  332.  
  333.                 GXRELEASE(pVertexBuffer);
  334.             }
  335.             else
  336.             {
  337.                 GXASSERT(ptmDrawMesh->GetOptions() & D3DXMESH_32BIT);
  338.  
  339.                 hr = ptmDrawMesh->LockVertexBuffer(D3DLOCK_READONLY, (PVOID*)&pbPoints);
  340.                 if (FAILED(hr))
  341.                     return hr;
  342.  
  343.                 hr = m_pIndexBuffer->Lock(0, 0, (PVOID*)&pdwLineIndices, D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY);
  344.                 if (FAILED(hr))
  345.                     return hr;
  346.  
  347.                 pbLine = (PBYTE)_alloca(m_cBytesPerVertex * 2);
  348.  
  349.                 iLineStart = iStartIndex * 2;
  350.                 iLineEnd = iLineStart + cLines * 2;
  351.                 for (iLine = iLineStart; iLine < iLineEnd; iLine+=2)
  352.                 {
  353.                     memcpy(pbLine, pbPoints + pdwLineIndices[iLine]*m_cBytesPerVertex, m_cBytesPerVertex);
  354.                     memcpy(pbLine + m_cBytesPerVertex, pbPoints + pdwLineIndices[iLine+1]*m_cBytesPerVertex, m_cBytesPerVertex);
  355.  
  356.                     hr = m_pDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, pbLine, m_cBytesPerVertex);
  357.                     if (FAILED(hr))
  358.                         return hr;
  359.                 }
  360.  
  361.                 ptmDrawMesh->UnlockVertexBuffer();
  362.                 m_pIndexBuffer->Unlock();
  363.             }
  364.         }
  365.     }
  366.     return S_OK;
  367. }
  368.  
  369. HRESULT
  370. CNPatchOutline::Draw(LPD3DXBASEMESH ptmDrawMesh, DWORD iSubset)
  371. {
  372.     if (iSubset < m_caeAttributeTable)
  373.         return DrawInternal(ptmDrawMesh, iSubset, UNUSED32, UNUSED32);
  374.     else
  375.         return S_OK;
  376. }
  377.  
  378. HRESULT
  379. CNPatchOutline::DrawFace(LPD3DXBASEMESH ptmDrawMesh, DWORD iFace, DWORD iSubset)
  380. {
  381.     if (iSubset < m_caeAttributeTable)
  382.         return DrawInternal(ptmDrawMesh, iSubset, iFace * m_cLinesPerOrigFace, m_cLinesPerOrigFace);
  383.     else
  384.         return S_OK;
  385. }
  386.  
  387. HRESULT
  388. CNPatchOutline::CreateEmptyOutline()
  389. {
  390.     delete []m_rgaeAttributeTable;
  391.     m_rgaeAttributeTable = NULL;
  392.     m_caeAttributeTable = 0;
  393.     GXRELEASE(m_pIndexBuffer);
  394.     GXRELEASE(m_pDevice);
  395.     GXRELEASE(m_pDeclObj);
  396.  
  397.     return S_OK;
  398. }
  399.